package com.sojoys.artifact.plugin.quartz;

import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.plugin.IPlugin;

public class QuartzPlugin implements IPlugin {

	static final Logger log = LoggerFactory.getLogger(QuartzPlugin.class);

	private static Scheduler scheduler = null;
	

	
	/**
	 * 添加调度任务
	 * @param triggerKey 全局唯一调度任务id
	 * @param cron 调度任务表达式
	 * @param classs 调度处理类
	 * @param param 调度任务参数
	 */
	public static void addJob(String name, String group,Date startAt, String cron, Class<? extends Job> classs, Map<String, Object> param){
		ScheduleBuilder<CronTrigger> schedBuilder = CronScheduleBuilder.cronSchedule(cron);
		addJob(name,group,startAt, schedBuilder, classs, param);
	}
	
	/**
	 * 添加调度任务
	 * @param name
	 * @param group
	 * @param startAt
	 * @param intervalInMillis 间隔时间毫秒
	 * @param repeatCount 执行次数 -1为不限次数
	 * @param classs
	 * @param param
	 */
	public static void addJob(String name, String group,Date startAt, int intervalInMillis,int repeatCount,Class<? extends Job> classs, Map<String, Object> param){
		ScheduleBuilder<SimpleTrigger> schedBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(intervalInMillis).withRepeatCount(repeatCount);    
		addJob(name,group,startAt, schedBuilder, classs, param);
	}
	
	/**
	 * 添加调度任务(高度定制)
	 * @param triggerKey 全局唯一调度任务id
	 * @param schedBuilder 调度任务表达式
	 * @param classs 调度处理类
	 * @param param 调度任务参数
	
	 * ScheduleBuilder常见调度类型
	 * 1.CronScheduleBuilder.cronSchedule(cron) // 轮询时间，表达式
	 * 2.SimpleScheduleBuilder.repeatHourlyForever(24) // 轮询时间，24小时
	 * 3.SimpleScheduleBuilder.repeatMinutelyForever(60) // 轮询时间，60分钟
	 * 4.SimpleScheduleBuilder.repeatSecondlyForever(60) // 轮询时间，60秒
	 * 5.SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10) //时间间隔
                        .withRepeatCount(5)        //重复次数(将执行6次)
	 */
	public static void addJob(String name, String group,Date startAt, ScheduleBuilder<? extends Trigger> schedBuilder, Class<? extends Job> classs, Map<String, Object> param){
		try {
			boolean exists = scheduler.checkExists(TriggerKey.triggerKey(name, group));
			if(exists){
				if(log.isWarnEnabled()) log.warn("调度任务已经存在 name = " + name + " group = " + group);
				return;
			}
			
			JobDetail jobDetail = JobBuilder.newJob(classs).withIdentity(name, group).build();
			
			if(param != null && !param.isEmpty()){
				jobDetail.getJobDataMap().putAll(param);
			}
			
			Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
					.withSchedule(schedBuilder) 
					.startAt(startAt)
					.build();
		
			scheduler.scheduleJob(jobDetail, trigger);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 修改调度
	 * @param name
	 * @param group
	 * @param startAt
	 * @param intervalInMillis
	 * @param repeatCount
	 */
	public static void modifyTime(String name, String group,Date startAt, int intervalInMillis,int repeatCount){
		ScheduleBuilder<SimpleTrigger> schedBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(intervalInMillis).withRepeatCount(repeatCount);
		modifyTime(name, group, startAt, schedBuilder);
	}
	
	/**
	 * 修改调度
	 * @param name
	 * @param group
	 * @param startAt
	 * @param cron
	 */
	public static void modifyTime(String name, String group,Date startAt, String cron){
		ScheduleBuilder<CronTrigger> schedBuilder = CronScheduleBuilder.cronSchedule(cron);
		modifyTime(name, group, startAt, schedBuilder);
	}
	/**
	 * 修改调度
	 * @param name
	 * @param group
	 * @param startAt
	 * @param schedBuilder
	 */
	public static void modifyTime(String name, String group,Date startAt, ScheduleBuilder<? extends Trigger> schedBuilder){       
        try {
            TriggerKey tk = TriggerKey.triggerKey(name, group);
            Trigger trg = TriggerBuilder.newTrigger().withIdentity(name, group)
					.withSchedule(schedBuilder) 
					.startAt(startAt)
					.build();
            scheduler.rescheduleJob(tk, trg);
            log.info("修改作业触发时间=> [作业名称：" + name + " 作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("修改作业触发时间=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
        }
    }
	
	/**
	 * 删除调度任务
	 * @param name
	 * @param group
	 */
	public static void removeJob(String name, String group){
        try {
            TriggerKey tk = TriggerKey.triggerKey(name, group);
            scheduler.pauseTrigger(tk);//停止触发器  
            scheduler.unscheduleJob(tk);//移除触发器
            JobKey jobKey = JobKey.jobKey(name, group);
            scheduler.deleteJob(jobKey);//删除作业
            log.info("删除作业=> [作业名称：" + name + " 作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("删除作业=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
        }
    }
	
	/**
	 * 删除调度任务
	 * @param name
	 * @param group
	 */
	public static void removeJob(String group){
        try {
        	GroupMatcher<TriggerKey> triggerKeyMatcher = GroupMatcher.groupEquals(group);
        	GroupMatcher<JobKey> jobKeyMatcher = GroupMatcher.groupEquals(group);
        	
        	scheduler.pauseTriggers(triggerKeyMatcher);//停止触发器
        	scheduler.unscheduleJobs(new ArrayList<>(scheduler.getTriggerKeys(triggerKeyMatcher)));//移除触发器
            scheduler.deleteJobs(new ArrayList<>(scheduler.getJobKeys(jobKeyMatcher)));//删除作业
            log.info("删除整组作业=> [作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("删除整组作业=> [作业组：" + group + "]=> [失败]");
        }
    }
     
	/**
	 * 暂停调度
	 * @param name
	 * @param group
	 */
    public static void pauseJob(String name, String group){
        try {
            JobKey jobKey = JobKey.jobKey(name, group);
            scheduler.pauseJob(jobKey);
            log.info("暂停作业=> [作业名称：" + name + " 作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("暂停作业=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
        }
    }
    
    /**
	 * 暂停调度
	 * @param name
	 * @param group
	 */
    public static void pauseJob(String group){
        try {
        	GroupMatcher<JobKey> jobKeyMatcher = GroupMatcher.groupEquals(group);
            scheduler.pauseJobs(jobKeyMatcher);
            log.info("暂停整组作业=> [作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("暂停整组作业=> [作业组：" + group + "]=> [失败]");
        }
    }
    
    /**
     * 暂停全部
     * @throws SchedulerException
     */
    public static void pauseAllJob() throws SchedulerException {  
    	try {
    		scheduler.pauseAll();  
            log.info("暂停全部作业=>  ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("暂停全部作业=> [失败]");
        }
    }
    
    /**
     * 恢复调度
     * @param name
     * @param group
     */
    public static void resumeJob(String name, String group){
        try {
            JobKey jobKey = JobKey.jobKey(name, group);         
            scheduler.resumeJob(jobKey);
            log.info("恢复作业=> [作业名称：" + name + " 作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("恢复作业=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
        }       
    }
    
    
    /**
     * 恢复调度
     * @param name
     * @param group
     */
    public static void resumeJob(String group){
        try {
        	GroupMatcher<JobKey> jobKeyMatcher = GroupMatcher.groupEquals(group);
            scheduler.resumeJobs(jobKeyMatcher);
            log.info("恢复整组作业=> 作业组：" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("恢复整组作业=> [作业组：" + group + "]=> [失败]");
        }       
    }
    
    /**
     * 恢复全部
     * @throws SchedulerException
     */
    public static void resumeAllJob() throws SchedulerException {  
    	try {
    		scheduler.resumeAll();  
            log.info("恢复全部作业=>  ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("恢复全部作业=> [失败]");
        }
    }
	
	
	@Override
	public boolean start() {
		if(scheduler == null){
			try {
				// 加载配置文件
				StdSchedulerFactory factory = new StdSchedulerFactory("quartz.properties");
				factory.initialize();
				
				scheduler = factory.getScheduler();
				scheduler.start();
			} catch (SchedulerException e) {
				if(log.isErrorEnabled()) log.error("初始化任务调度出错", e);
			}
		}
		return true;
	}

	@Override
	public boolean stop() {
		try {
			if (scheduler != null && !scheduler.isShutdown()) {
				scheduler.shutdown();
				int i = 1;
				while (!scheduler.isShutdown()) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					log.info("QuartzPlugin shutdown...{}",i);
					i++;
				}
			}
		} catch (SchedulerException e) {
			if(log.isErrorEnabled()) log.error("关闭任务调度出错", e);
		}
		return true;
	}

}
